package cn.com.code.generator.interceptor;


import cn.com.do1.dsf.common.utils.AESEncryptUtils;
import cn.com.do1.dsf.common.utils.Sm4Utils;
import cn.com.do1.dsf.compont.mysql.annotation.SecurityData;
import cn.com.do1.dsf.compont.mysql.utils.ReflectUtils;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.sql.Wrapper;
import java.util.*;
import java.util.Map.Entry;

@Intercepts({@Signature(
        type = Executor.class,
        method = "update",
        args = {MappedStatement.class, Object.class}
), @Signature(
        type = Executor.class,
        method = "query",
        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
)})
public class DataEncryptInterceptor1 implements Interceptor {
    private final Logger logger = LoggerFactory.getLogger(cn.com.do1.dsf.compont.mysql.dataencrypt.DataEncryptInterceptor.class);
    private static final int RECURSION_TIME = 10;
    @Value("${do1.dataencrypt-secret:null}")
    private String secretKey;
    @Value("${do1.isGuoMi:false}")
    private Boolean isGuoMi;

    public DataEncryptInterceptor1() {
    }

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement statement = (MappedStatement)invocation.getArgs()[0];
        String methodName = invocation.getMethod().getName();
        Object[] args = invocation.getArgs();
        Object parameter = args[1];
        this.doSecurityParse(parameter, 1);
        Object returnValue = invocation.proceed();
        this.doSecurityParse(parameter, 0);
        this.handleField(returnValue, 0, 0);
        return returnValue;
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
    }

    public void doSecurityParse(Object parameter, int type) {
        if (parameter instanceof HashMap) {
            HashMap<String, Object> hashMap = (HashMap)parameter;
            List<Object> handledParam = new ArrayList();
            Iterator var5 = hashMap.entrySet().iterator();

            while(var5.hasNext()) {
                Entry<String, Object> entry = (Entry)var5.next();
                if (!handledParam.contains(entry.getValue())) {
                    this.doSecurityParse(entry.getValue(), type);
                    handledParam.add(entry.getValue());
                }
            }
        } else if (parameter instanceof Set) {
            Set<Object> hashSet = (HashSet)parameter;
            Iterator var8 = hashSet.iterator();

            while(var8.hasNext()) {
                Object entry = var8.next();
                this.doSecurityParse(entry, type);
            }
        }

        if (parameter != null && !isBaseType(parameter)) {
            this.handleField(parameter, type, 0);
        }

    }

    public void handleField(Object parameter, int type, int time) {
        ++time;
        if (time <= 10) {
            try {
                Iterator securityData;
                Object val;
                if (parameter instanceof ArrayList) {
                    List<?> list = (ArrayList)parameter;
                    securityData = list.iterator();

                    while(securityData.hasNext()) {
                        val = securityData.next();
                        if (val != null && !isBaseType(val)) {
                            this.handleField(val, type, time);
                        }
                    }
                }

                if (parameter == null || isBaseType(parameter)) {
                    return;
                }

                Field[] fields = ReflectUtils.getClassFieldsAndSuperClassFields(parameter.getClass());
                securityData = null;
                val = null;
                Field[] var7 = fields;
                int var8 = fields.length;

                for(int var9 = 0; var9 < var8; ++var9) {
                    Field field = var7[var9];
                    field.setAccessible(true);
                    Object object = field.get(parameter);
                    if (object != null && !isBaseType(object)) {
                        this.handleField(object, type, time);
                    }

                    SecurityData sec1 = (SecurityData)field.getAnnotation(SecurityData.class);
                    if (sec1 != null) {
                        String obj = (String)field.get(parameter);
                        if (obj != null) {
                            field.set(parameter, this.doEncrypt(obj, type));
                        }

                        field.setAccessible(false);
                    }
                }
            } catch (Exception var12) {
                var12.printStackTrace();
            }

        }
    }

    public String doEncrypt(String str, int type) {
        String result;
        if (!this.isGuoMi) {
            if (this.secretKey != null && !"null".equals(this.secretKey)) {
                result = type == 1 ? AESEncryptUtils.encrypt(str, this.secretKey) : AESEncryptUtils.decrypt(str, this.secretKey);
            } else {
                result = type == 1 ? AESEncryptUtils.encrypt(str) : AESEncryptUtils.decrypt(str);
            }
        } else if (this.secretKey != null && !"null".equals(this.secretKey)) {
            result = type == 1 ? Sm4Utils.encryptEcb(this.secretKey, str) : Sm4Utils.decryptEcb(this.secretKey, str);
        } else {
            result = type == 1 ? AESEncryptUtils.encrypt(str) : AESEncryptUtils.decrypt(str);
        }

        return type != 1 && result == null ? str : result;
    }

    public static boolean isBaseType(Object object) {
        return object instanceof Integer || object instanceof Byte || object instanceof Long || object instanceof Double || object instanceof Float || object instanceof Character || object instanceof Short || object instanceof Boolean || object instanceof String || object instanceof BigDecimal || object instanceof Map || object instanceof List || object instanceof Set || object instanceof Iterator || object instanceof Date || object instanceof Array || object instanceof Wrapper || object instanceof com.baomidou.mybatisplus.mapper.Wrapper || object.getClass().isEnum();
    }
}